package com.binc.testspring.study.nio.netty.groupChat;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * FileName: Netty_group_chat_server_childChannel
 * Autho: binC
 * Date:  2022/4/20 16:23
 */
public class Netty_group_chat_server_childChannel extends SimpleChannelInboundHandler<String> {
   /*
    new ChannelInitializer<SocketChannel>() { // 创建一个通道初始化对象(匿名对象)
        /**
         * 给pipleline(管道) 设置处理器    其实就是真正的业务处理handler
         * 匿名内部类  需要重写一个方法
         *
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            // 在这个位置我们第一次拿到 并为这个channel做了一些操作,   这个时候如果我们维护一个集合将channel放到集合中,在推送系统的时候,我们可以获得到这个channel,然后将业务放到这个channel对应的eventLoop的taskQueue或者scheduleTaskqueuezhong
            ch.pipeline().addLast(new My_server_Handler2());//这里设置的是自定义的handler
        }
    }
     这里注释掉的内容就是当时在server端给childHandler 这是的内容,当时的设置的内容不是很多,我们将为这个单独建立了一个类进行设置;当时想做的集合在当前类中也用了,用的还是netty提供的集合
       netty提供的channelGroup提供的方法和部分机制比我们自行维护一个集合好很多,省的我们去remove 和遍历了
    */

    private  static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
        handlerAdded 表示连接建立，一旦连接，第一个被执行
            将当前channel 加入到  channelGroup
                我们本需求中要求通知其他人我上线了
     * @param ctx
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();

        //加入channelGroup之前先通知其他人我上线了,  在这个收加入就用考虑排除自己的问题了
        channelGroup.writeAndFlush("[客户端]"+channel.remoteAddress()+"加入群聊了"+sdf.format(new Date()));

        //加入channelGroup集合
        channelGroup.add(channel);
        System.out.println("有新的客户端连接进来了,channelGroup size" + channelGroup.size());

    }


    /**
      断开连接的时候,要求提示别的客户但我下线了
     * @param ctx
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //channelGroup.remove(channel); // 这个不需要吗?
        channelGroup.writeAndFlush("[客户端]" + channel.remoteAddress() + " 离开了\n");
        System.out.println("有客户端断开连接了channelGroup size" + channelGroup.size());

    }


    //表示channel 处于活动状态, 提示 xx上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //这个是给服务端看的，客户端上面已经提示xxx加入群聊了
        System.out.println(ctx.channel().remoteAddress() + " 上线了~");
    }

    //表示channel 处于不活动状态, 提示 xx离线了
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        System.out.println(ctx.channel().remoteAddress() + " 离线了~");
    }


    /**
        读取客户端发送的数据,转发给在线的其他客户端
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //获取到当前的channel
        Channel channel = ctx.channel();

        // msg 是服务端收到的任意客户端发送的消息,我需要将这个消息发送给别的客户端,   注意排除自己
        channelGroup.forEach(ch ->{
            if (ch != channel) {
                ch.writeAndFlush("[客户]" + channel.remoteAddress() + "发送了消息{" + msg + "}" + sdf.format(new Date()) + "\n");
            } else {
                // 这是自己发的消息,不用处理了
            }
        });
    }

    /**
      发生异常的时候,关闭通道
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
